import tkinter as tk
from tkinter import filedialog, messagebox, ttk

from ..core.data_loader import DataLoader
from ..models.data_source import DataSource, SourceType
from ..utils.logger import logger
from .db_config_dialog import DatabaseConfigDialog
from .mapping_dialog import MappingDialog


class SourceManager:
    """数据源管理功能"""

    def __init__(self, window):
        """初始化数据源管理器"""
        self.window = window
        self.source1_frame = None
        self.source2_frame = None
        self.source1 = None  # 添加数据源1
        self.source2 = None  # 添加数据源2
        self.source1_path_var = None
        self.source2_path_var = None

    def _create_source_frame(self, parent):
        """创建数据源配置区域"""
        config_frame = ttk.Frame(parent)
        config_frame.pack(fill=tk.X, padx=10, pady=5)

        # 创建数据源1和数据源2，并保存引用
        self.source1_frame = self._create_source_group(config_frame, "数据源1")
        self.source2_frame = self._create_source_group(config_frame, "数据源2")

        return config_frame

    def _create_source_group(self, parent, title):
        """创建数据源配置组"""
        group = ttk.LabelFrame(parent, text=title)
        group.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5, pady=5)

        # 数据源类型选择
        type_frame = ttk.Frame(group)
        type_frame.pack(fill=tk.X, padx=5, pady=5)

        ttk.Label(type_frame, text="数据源类型:").pack(side=tk.LEFT)
        type_var = tk.StringVar()
        type_combo = ttk.Combobox(
            type_frame,
            textvariable=type_var,
            values=[t.value for t in SourceType],
            state="readonly",
        )
        type_combo.pack(side=tk.LEFT, padx=5)
        type_combo.bind(
            "<<ComboboxSelected>>",
            lambda e: self._on_source_type_changed(group, SourceType(type_var.get())),
        )

        # 添加路径显示标签
        path_var = tk.StringVar()
        path_label = ttk.Label(group, textvariable=path_var)
        path_label.pack(fill=tk.X, padx=5, pady=5)

        # 保存路径显示变量
        if title == "数据源1":
            self.source1_path_var = path_var
        else:
            self.source2_path_var = path_var

        # 初始化框架属性
        group.path = ""
        group.type = None
        group.db_config = {}
        group.mapping = {}

        return group

    def _on_source_type_changed(self, frame, source_type):
        """数据源类型改变处理"""
        # 清除旧的配置控件
        for widget in frame.winfo_children():
            if (
                isinstance(widget, ttk.Frame)
                and widget.winfo_name() != "!frame"
                and widget.winfo_name() != "config_frame"
            ):
                widget.destroy()

        # 创建新的配置控件
        config_frame = ttk.Frame(frame, name="config_frame")
        config_frame.pack(fill=tk.X, padx=5, pady=5)

        if source_type == SourceType.DATABASE:
            ttk.Button(
                config_frame,
                text="配置数据库",
                command=lambda: self._on_config_database(frame),
            ).pack(side=tk.LEFT)
        else:
            ttk.Button(
                config_frame,
                text="选择文件",
                command=lambda: self._on_select_file(frame, source_type),
            ).pack(side=tk.LEFT)

        # 添加字段映射按钮
        ttk.Button(
            config_frame,
            text="字段映射",
            command=lambda: self._on_mapping_fields(frame),
        ).pack(side=tk.LEFT, padx=5)

    def _on_config_database(self, frame):
        """配置数据库连接"""
        try:
            # 准备现有配置
            existing_config = None
            if hasattr(frame, "path") and hasattr(frame, "db_config"):
                existing_config = {"path": frame.path, "db_config": frame.db_config}

            # 传入现有配置
            dialog = DatabaseConfigDialog(self.window, existing_config)
            dialog.wait_window()

            if dialog.result:
                # 更新数据源配置
                source = DataSource(
                    type=SourceType.DATABASE,
                    path=dialog.result["path"],
                    db_config=dialog.result["db_config"],
                )

                # 设置数据源
                if frame == self.source1_frame:
                    self.source1 = source
                    frame.db_config = dialog.result["db_config"]
                    self.source1_path_var.set(
                        f"数据库: {source.db_config['type']}@{source.db_config['host']}"
                    )
                else:
                    self.source2 = source
                    frame.db_config = dialog.result["db_config"]
                    self.source2_path_var.set(
                        f"数据库: {source.db_config['type']}@{source.db_config['host']}"
                    )

                # 保存路径和配置到框架
                frame.path = dialog.result["path"]
                frame.type = SourceType.DATABASE
                frame.db_config = dialog.result["db_config"]
                frame.mapping = {}  # 初始化映射关系

                logger.info(f"数据库配置已保存: {source.db_config}")

        except Exception as e:
            logger.error(f"配置数据库失败: {str(e)}", exc_info=True)
            messagebox.showerror("错误", f"配置失败: {str(e)}")

    def _on_select_file(self, frame, source_type):
        """选择文件"""
        file_types = []
        if source_type == SourceType.EXCEL:
            file_types = [("Excel文件", "*.xlsx"), ("Excel文件", "*.xls")]
        elif source_type == SourceType.CSV:
            file_types = [("CSV文件", "*.csv")]
        elif source_type == SourceType.JSON:
            file_types = [("JSON文件", "*.json")]

        file_types.append(("所有文件", "*.*"))

        file_path = filedialog.askopenfilename(
            filetypes=file_types,
            title="选择文件",
        )
        if not file_path:
            return

        try:
            # 保存当前的字段映射
            old_mapping = getattr(frame, "field_mapping", {})
            old_path = getattr(frame, "path", "")

            # 更新文件路径
            frame.path = file_path
            frame.type = source_type

            # 加载新文件的字段
            loader = DataLoader(source_type, file_path)
            new_fields = loader.get_fields()

            if old_path and old_mapping:
                # 创建新的字段映射，保留有效的映射关系
                new_mapping = {}
                for source_field, target_field in old_mapping.items():
                    if source_field in new_fields:
                        new_mapping[source_field] = target_field
                frame.field_mapping = new_mapping
                logger.info(f"保留了有效的字段映射: {new_mapping}")
            else:
                frame.field_mapping = {}

            logger.info(
                f"设置数据源配置: type={source_type}, path={file_path}, mapping={frame.field_mapping}"
            )

        except Exception as e:
            logger.error(f"选择文件失败: {str(e)}", exc_info=True)
            messagebox.showerror("错误", f"选择文件失败: {str(e)}")

    def _on_mapping_fields(self, frame):
        """字段映射"""
        try:
            # 获取数据源类型和路径
            type_combo = None
            for widget in frame.winfo_children():
                if isinstance(widget, ttk.Frame):
                    for child in widget.winfo_children():
                        if isinstance(child, ttk.Combobox):
                            type_combo = child
                            break
                    if type_combo:
                        break

            if not type_combo or not type_combo.get():
                messagebox.showerror("错误", "请先选择数据源类型")
                return

            source_type = SourceType(type_combo.get())
            path = getattr(frame, "path", None)
            db_config = getattr(frame, "db_config", None)  # 获取数据库配置

            if not path:
                messagebox.showerror("错误", "请先选择数据源")
                return

            if source_type == SourceType.DATABASE and not db_config:
                messagebox.showerror("错误", "请先配置数据库")
                return

            # 打开映射对话框
            dialog = MappingDialog(
                self.window,
                self.data_fields,
                source_type,
                path,
                getattr(frame, "mapping", {}),
                (
                    db_config if source_type == SourceType.DATABASE else None
                ),  # 传递数据库配置
            )
            self.window.wait_window(dialog)

            if dialog.result:
                frame.mapping = dialog.result
                logger.info(f"更新字段映射: {dialog.result}")

        except Exception as e:
            logger.error(f"字段映射失败: {str(e)}", exc_info=True)
            messagebox.showerror("错误", f"字段映射失败: {str(e)}")

    def _find_source_frame(self, title):
        """查找数据源配置框架"""
        for widget in self.window.winfo_children():
            if isinstance(widget, ttk.Frame):
                for child in widget.winfo_children():
                    if (
                        isinstance(child, ttk.LabelFrame)
                        and child.cget("text") == title
                    ):
                        return child
        return None

    def _create_data_source(self, frame) -> DataSource:
        """从配置框架创建数据源配置"""
        if not frame:
            return None

        # 获取数据源类型
        type_combo = None
        for widget in frame.winfo_children():
            if isinstance(widget, ttk.Frame):
                for child in widget.winfo_children():
                    if isinstance(child, ttk.Combobox):
                        type_combo = child
                        break
                if type_combo:
                    break

        if not type_combo or not type_combo.get():
            return None

        source_type = SourceType(type_combo.get())
        path = frame.path if hasattr(frame, "path") else ""
        mapping = frame.mapping if hasattr(frame, "mapping") else {}
        db_config = frame.db_config if hasattr(frame, "db_config") else {}

        # 使用正确的参数名 mapping 而不是 field_mapping
        return DataSource(
            type=source_type,
            path=path,
            mapping=mapping,  # 这里改为 mapping
            db_config=db_config,
        )

    def _set_source_config(self, frame, source_type, path, mapping):
        """设置数据源配置"""
        if not frame:
            return

        try:
            # 清除旧的显示内容
            for widget in frame.winfo_children():
                if isinstance(widget, ttk.Label) or (
                    isinstance(widget, ttk.Frame)
                    and widget.winfo_name() != "!frame"
                    and widget.winfo_name() != "config_frame"
                ):
                    widget.destroy()

            # 设置数据源类型
            type_combo = None
            for widget in frame.winfo_children():
                if isinstance(widget, ttk.Frame):
                    for child in widget.winfo_children():
                        if isinstance(child, ttk.Combobox):
                            type_combo = child
                            break
                    if type_combo:
                        break

            if not type_combo:
                logger.warning("未找到数据源类型选择框")
                return

            # 设置类型
            type_combo.set(source_type.value)

            # 触发类型改变事件
            self._on_source_type_changed(frame, source_type)

            # 保存路径和映射
            frame.path = path
            frame.mapping = mapping

            # 更新路径显示
            if source_type != SourceType.DATABASE:
                path_label = ttk.Label(frame, text=f"已选择: {path}")
                path_label.pack(fill=tk.X, padx=5, pady=5)

            logger.info(
                f"设置数据源配置: type={source_type.value}, path={path}, mapping={mapping}"
            )

        except Exception as e:
            logger.error(f"设置数据源配置失败: {str(e)}", exc_info=True)
            messagebox.showerror("错误", f"设置数据源配置失败: {str(e)}")
